package code;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import labeling.Labeling3Classes;
import math.RMSE;
import model.MF;
import data.Data;
import file.Parser;

public class TenFoldCrossValidation_SVMModel {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		
		String dir = "D:/Netflix Dataset/download/training_set/";
		
		Parser parseTrain = new Parser(dir+"smalltrain");
		List<Data> train = parseTrain.getList();
		
		Parser parseTest = new Parser(dir+"smallvalidate");
		List<Data> test = parseTest.getList();
		
		int k = 5;
		double gamma = 0.02;
		double lambda = 0.02;
		double epsilon = 0.15;
		
		System.out.println("k: "+k);
		System.out.println("gamma: "+gamma);
		System.out.println("lambda: "+lambda);
		
		MF mf = new MF(k, gamma, lambda, train);		
		double avg = mf.getAvgTrain();
		double[] ubias = mf.getUbias();
		double[] ibias = mf.getIbias();
		double[] ufactor = mf.getUfactor();
		double[] ifactor = mf.getIfactor();
		
		System.out.println("Average: "+avg);
		System.out.println("max user ubias: "+ubias.length);
		System.out.println("number of ibias: "+ibias.length);
		System.out.println("number of ufactor: "+ufactor.length);
		System.out.println("number of ifactor: "+ifactor.length);
		
		Labeling3Classes labelTrain = new Labeling3Classes(train, avg, ubias, ibias, epsilon);
		List<Data> postrain = labelTrain.getPos();
		List<Data> negtrain = labelTrain.getNeg();
		List<Data> neutrain = labelTrain.getNeu();

		MF pmf = new MF(k, gamma, lambda, postrain);	
		double pavg = pmf.getAvgTrain();
		double[] uposbias = pmf.getUbias();
		double[] iposbias = pmf.getIbias();
		double[] uposfactor = pmf.getUfactor();
		double[] iposfactor = pmf.getIfactor();	
		
		MF nmf = new MF(k, gamma, lambda, negtrain);
		double navg = nmf.getAvgTrain();
		double[] unegbias = nmf.getUbias();
		double[] inegbias = nmf.getIbias();
		double[] unegfactor = nmf.getUfactor();
		double[] inegfactor = nmf.getIfactor();
		
		int np = 0;
		int nn = 0;
		int n0 = 0;
		
		List<Double> predict = new ArrayList<Double>();
		BufferedReader output = new BufferedReader(new FileReader("C:\\Users\\mtnguyen.2012\\Downloads\\svm_light_windows (1)\\ordinal_classifier\\output015"));
		BufferedReader output2 = new BufferedReader(new FileReader("C:\\Users\\mtnguyen.2012\\Downloads\\svm_light_windows (1)\\ordinal_classifier\\output015_"));
		double minThres = 1;
		double minThres2 = minThres;
		String line;
		Iterator<Data> it = test.iterator();
		List<Double> predict3 = new ArrayList<Double>();
		List<Data> real = new ArrayList<Data>();
		List<Double> predict32 = new ArrayList<Double>();
		List<Data> real2 = new ArrayList<Data>();
		List<Double> predict33 = new ArrayList<Double>();
		List<Data> real3 = new ArrayList<Data>();
		while((line = output.readLine()) != null){
			Data datum = it.next();
			int uid = datum.uid;
			short iid = datum.iid;
			double pred = 0.0;
			double cls = Double.parseDouble(line);
			if (cls > 0) {
				if (cls > minThres) {
					//use positive model
					np++;
					pred = pavg + uposbias[uid-1] + iposbias[iid-1];
					for(int j=0; j<k; j++){
						pred += uposfactor[k*(uid-1)+j]*iposfactor[k*(iid-1)+j];
					}
				}
				else {
					//user default model
					n0++;
					pred = avg + ubias[uid-1] + ibias[iid-1];
					for(int j=0; j<k; j++){
						pred += ufactor[k*(uid-1)]*ifactor[k*(iid-1)+j];
					}
				}
				real3.add(datum);
				predict33.add(pred);
			}
			else {
				String line2 = output2.readLine();
				double cls2 = Double.parseDouble(line2);
				if (cls2 > minThres2){
					//use negative model
					nn++;
					pred = navg + unegbias[uid-1] + inegbias[iid-1];
					for(int j=0; j<k; j++){
						pred += unegfactor[k*(uid-1)+j]*inegfactor[k*(iid-1)+j];
					}
					real2.add(datum);
					predict32.add(pred);
				}
				else {
					//user default model
					n0++;
					pred = avg + ubias[uid-1] + ibias[iid-1];
					for(int j=0; j<k; j++){
						pred += ufactor[k*(uid-1)]*ifactor[k*(iid-1)+j];
					}
					real.add(datum);
					predict3.add(pred);
				}
			}
			predict.add(pred);
		}

		output.close();
		output2.close();
		
		
		Iterator<Data> it2 = test.iterator();
		BufferedReader ground = new BufferedReader(new FileReader("C:\\Users\\mtnguyen.2012\\Downloads\\svm_light_windows (1)\\ordinal_classifier\\groundtruth015"));
		List<Double> predict2 = new ArrayList<Double>();
		while((line = ground.readLine()) != null){
			Data datum = it2.next();
			int uid = datum.uid;
			short iid = datum.iid;
			int sign = Integer.parseInt(line);
			double pred = 0.0;
			if(sign > 0) {
				pred = pavg + uposbias[uid-1] + iposbias[iid-1];
				for(int j=0; j<k; j++){
					pred += uposfactor[k*(uid-1)+j]*iposfactor[k*(iid-1)+j];
				}
			}
			
			else if (sign < 0) {
				pred = navg + unegbias[uid-1] + inegbias[iid-1];
				for(int j=0; j<k; j++){
					pred += unegfactor[k*(uid-1)+j]*inegfactor[k*(iid-1)+j];
				}
				
			}
			else {
				pred = avg + ubias[uid-1] + ibias[iid-1];
				for(int j=0; j<k; j++){
					pred += ufactor[k*(uid-1)]*ifactor[k*(iid-1)+j];
				}
			}
			predict2.add(pred);
		}
		ground.close();
		
		System.out.println("Num pos "+np);
		System.out.println("Num neg "+nn);
		System.out.println("Num neu "+n0);
		
		System.out.println("RMSE "+RMSE.RMSE(test, predict));
		
		System.out.println("RMSE "+RMSE.RMSE(test, predict2));
		
		System.out.println("RMSE "+RMSE.RMSE(real, predict3));
		
		System.out.println("RMSE "+RMSE.RMSE(real2, predict32));
		
		System.out.println("RMSE "+RMSE.RMSE(real3, predict33));
	}

}
